﻿using OdooRpcClient.Converters;
using PortaCapena.OdooJsonRpcClient;
using PortaCapena.OdooJsonRpcClient.Models;
using ScintillaNET;
using Sunny.UI;
using System;
using System.Drawing;
using WebAssistant.BusinessLogic;
using WebAssistant.Common;

namespace Assistant.Tools
{
    public partial class FormReportModel : UITitlePage
    {
		static OdooConfig config = new OdooConfig(
			apiUrl: "",
			dbName: "",
			userName: "",
			password: ""
			);
		static OdooClient odooClient = new OdooClient(config);


		public FormReportModel()
        {
            InitializeComponent();
			InitializeOdoo();
			//InitializeLanguage();
            InitializeEdit();
        }

		private void InitializeOdoo()
		{
			string[] ConfigKeyList = new string[] {
				"odoo.server.url", "odoo.server.database", "odoo.server.user", "odoo.key", "odoo.server.password"
			};
			foreach (string configkey in ConfigKeyList)
			{
				if (!DataAccess.CheckSettingExists(configkey))
				{
					ShowWarningDialog("Odoo服务器配置错误！请设置。");
					return;
				}
			}
			config = new OdooConfig(
				apiUrl: DataAccess.GetSettingByKey("odoo.server.url"),
				dbName: DataAccess.GetSettingByKey("odoo.server.database"),
				userName: DataAccess.GetSettingByKey("odoo.server.user"),
				password: SecurityHelper.DecryptString(DataAccess.GetSettingByKey("odoo.server.password"), DataAccess.GetSettingByKey("odoo.key"))
				);
			odooClient = new OdooClient(config);
		}

		#region 语言选择

		//private async void InitializeLanguage()
		//{
		//	var loginResult = await odooClient.LoginAsync();
		//	if (loginResult.Failed)
		//	{
		//		ShowInfoDialog("登陆验证失败，请检查配置是否正确");
		//	}
		//	else if (loginResult.Succeed)
  //          {
		//		var repository = new OdooRepository<LangOdooModel>(config);
		//		var languages = await repository.Query()
		//			.Where(x => x.Active, OdooOperator.EqualsTo, true)
		//			.Select(x => new
		//			{
		//				x.DisplayName,
		//				x.Code,
		//			})
		//			.ToListAsync();
  //              if (languages.Succeed)
  //              {
  //                  comboBoxLanguage.ValueMember = "Code";
  //                  comboBoxLanguage.DisplayMember = "DisplayName";
  //                  comboBoxLanguage.DataSource = languages.Value;
  //              }			
		//	}
		//}

		#endregion

		#region 代码编辑器
		private void InitializeEdit()
        {
			//uiPanel1.Height = this.Height - uiPanel2.Height;
			// 基本配置 
			scintillaEdit.Dock = System.Windows.Forms.DockStyle.Fill;
            scintillaEdit.TextChanged += (this.OnTextChanged);

			// 初始视图配置 
			scintillaEdit.WrapMode = WrapMode.None;
            scintillaEdit.IndentationGuides = IndentView.LookBoth;

            // STYLING
            InitColors();
            InitSyntaxColoring();

            // 行号
            InitNumberMargin();

            // BOOKMARK MARGIN
            InitBookmarkMargin();

            // CODE FOLDING MARGIN
            InitCodeFolding();
        }

		private void InitColors()
		{
			scintillaEdit.SetSelectionBackColor(true, IntToColor(0x114D9C));
		}


		private void InitSyntaxColoring()
		{
			// 配置默认样式 
			scintillaEdit.StyleResetDefault();
			scintillaEdit.Styles[ScintillaNET.Style.Default].Font = "Consolas";
			scintillaEdit.Styles[ScintillaNET.Style.Default].Size = 10;
			scintillaEdit.Styles[ScintillaNET.Style.Default].BackColor = IntToColor(0x212121);
			scintillaEdit.Styles[ScintillaNET.Style.Default].ForeColor = IntToColor(0xFFFFFF);
			scintillaEdit.StyleClearAll();

			// 配置 CPP (C#) 词法分析器样式 
			scintillaEdit.Styles[ScintillaNET.Style.Cpp.Identifier].ForeColor = IntToColor(0xD0DAE2);
			scintillaEdit.Styles[ScintillaNET.Style.Cpp.Comment].ForeColor = IntToColor(0xBD758B);
			scintillaEdit.Styles[ScintillaNET.Style.Cpp.CommentLine].ForeColor = IntToColor(0x40BF57);
			scintillaEdit.Styles[ScintillaNET.Style.Cpp.CommentDoc].ForeColor = IntToColor(0x2FAE35);
			scintillaEdit.Styles[ScintillaNET.Style.Cpp.Number].ForeColor = IntToColor(0xFFFF00);
			scintillaEdit.Styles[ScintillaNET.Style.Cpp.String].ForeColor = IntToColor(0xFFFF00);
			scintillaEdit.Styles[ScintillaNET.Style.Cpp.Character].ForeColor = IntToColor(0xE95454);
			scintillaEdit.Styles[ScintillaNET.Style.Cpp.Preprocessor].ForeColor = IntToColor(0x8AAFEE);
			scintillaEdit.Styles[ScintillaNET.Style.Cpp.Operator].ForeColor = IntToColor(0xE0E0E0);
			scintillaEdit.Styles[ScintillaNET.Style.Cpp.Regex].ForeColor = IntToColor(0xff00ff);
			scintillaEdit.Styles[ScintillaNET.Style.Cpp.CommentLineDoc].ForeColor = IntToColor(0x77A7DB);
			scintillaEdit.Styles[ScintillaNET.Style.Cpp.Word].ForeColor = IntToColor(0x48A8EE);
			scintillaEdit.Styles[ScintillaNET.Style.Cpp.Word2].ForeColor = IntToColor(0xF98906);
			scintillaEdit.Styles[ScintillaNET.Style.Cpp.CommentDocKeyword].ForeColor = IntToColor(0xB3D991);
			scintillaEdit.Styles[ScintillaNET.Style.Cpp.CommentDocKeywordError].ForeColor = IntToColor(0xFF0000);
			scintillaEdit.Styles[ScintillaNET.Style.Cpp.GlobalClass].ForeColor = IntToColor(0x48A8EE);

			scintillaEdit.Lexer = Lexer.Cpp;

			scintillaEdit.SetKeywords(0, "class extends implements import interface new case do while else if for in switch throw get set function var try catch finally while with default break continue delete return each const namespace package include use is as instanceof typeof author copy default deprecated eventType example exampleText exception haxe inheritDoc internal link mtasc mxmlc param private return see serial serialData serialField since throws usage version langversion playerversion productversion dynamic private public partial static intrinsic internal native override protected AS3 final super this arguments null Infinity NaN undefined true false abstract as base bool break by byte case catch char checked class const continue decimal default delegate do double descending explicit event extern else enum false finally fixed float for foreach from goto group if implicit in int interface internal into is lock long new null namespace object operator out override orderby params private protected public readonly ref return switch struct sbyte sealed short sizeof stackalloc static string select this throw true try typeof uint ulong unchecked unsafe ushort using var virtual volatile void while where yield");
			scintillaEdit.SetKeywords(1, "void Null ArgumentError arguments Array Boolean Class Date DefinitionError Error EvalError Function int Math Namespace Number Object RangeError ReferenceError RegExp SecurityError String SyntaxError TypeError uint XML XMLList Boolean Byte Char DateTime Decimal Double Int16 Int32 Int64 IntPtr SByte Single UInt16 UInt32 UInt64 UIntPtr Void Path File System Windows Forms ScintillaNET");

		}

		private void OnTextChanged(object sender, EventArgs e)
		{

		}


		#region Numbers, Bookmarks, Code Folding

		/// <summary>
		/// 文本区域的背景颜色 
		/// </summary>
		private const int BACK_COLOR = 0x2A211C;

		/// <summary>
		/// 文本区域的默认文本颜色 
		/// </summary>
		private const int FORE_COLOR = 0xB7B7B7;

		/// <summary>
		/// 将此更改为您希望行号显示的任何边距 
		/// </summary>
		private const int NUMBER_MARGIN = 1;

		/// <summary>
		/// 将此更改为您希望书签/断点显示的任何边距 
		/// </summary>
		private const int BOOKMARK_MARGIN = 2;
		private const int BOOKMARK_MARKER = 2;

		/// <summary>
		/// 将此更改为您希望代码折叠树 (+/-) 显示的任何边距
		/// </summary>
		private const int FOLDING_MARGIN = 3;

		/// <summary>
		/// 将此设置为 true 以显示用于代码折叠的圆形按钮（边距上的 [+] 和 [-] 按钮） 
		/// </summary>
		private const bool CODEFOLDING_CIRCULAR = true;

		private void InitNumberMargin()
		{

			scintillaEdit.Styles[ScintillaNET.Style.LineNumber].BackColor = IntToColor(BACK_COLOR);
			scintillaEdit.Styles[ScintillaNET.Style.LineNumber].ForeColor = IntToColor(FORE_COLOR);
			scintillaEdit.Styles[ScintillaNET.Style.IndentGuide].ForeColor = IntToColor(FORE_COLOR);
			scintillaEdit.Styles[ScintillaNET.Style.IndentGuide].BackColor = IntToColor(BACK_COLOR);

			var nums = scintillaEdit.Margins[NUMBER_MARGIN];
			nums.Width = 30;
			nums.Type = MarginType.Number;
			nums.Sensitive = true;
			nums.Mask = 0;

			scintillaEdit.MarginClick += TextArea_MarginClick;
		}

		private void InitBookmarkMargin()
		{

			//scintillaEdit.SetFoldMarginColor(true, IntToColor(BACK_COLOR));

			var margin = scintillaEdit.Margins[BOOKMARK_MARGIN];
			margin.Width = 20;
			margin.Sensitive = true;
			margin.Type = MarginType.Symbol;
			margin.Mask = (1 << BOOKMARK_MARKER);
			//margin.Cursor = MarginCursor.Arrow;

			var marker = scintillaEdit.Markers[BOOKMARK_MARKER];
			marker.Symbol = MarkerSymbol.Circle;
			marker.SetBackColor(IntToColor(0xFF003B));
			marker.SetForeColor(IntToColor(0x000000));
			marker.SetAlpha(100);

		}

		private void InitCodeFolding()
		{

			scintillaEdit.SetFoldMarginColor(true, IntToColor(BACK_COLOR));
			scintillaEdit.SetFoldMarginHighlightColor(true, IntToColor(BACK_COLOR));

			// 启用代码折叠 
			scintillaEdit.SetProperty("fold", "1");
			scintillaEdit.SetProperty("fold.compact", "1");

			// 配置边距以显示折叠符号 
			scintillaEdit.Margins[FOLDING_MARGIN].Type = MarginType.Symbol;
			scintillaEdit.Margins[FOLDING_MARGIN].Mask = Marker.MaskFolders;
			scintillaEdit.Margins[FOLDING_MARGIN].Sensitive = true;
			scintillaEdit.Margins[FOLDING_MARGIN].Width = 20;

			// 为所有折叠标记设置颜色 
			for (int i = 25; i <= 31; i++)
			{
				scintillaEdit.Markers[i].SetForeColor(IntToColor(BACK_COLOR)); // styles for [+] and [-]
				scintillaEdit.Markers[i].SetBackColor(IntToColor(FORE_COLOR)); // styles for [+] and [-]
			}

			// 使用相应的符号配置折叠标记 
			scintillaEdit.Markers[Marker.Folder].Symbol = CODEFOLDING_CIRCULAR ? MarkerSymbol.CirclePlus : MarkerSymbol.BoxPlus;
			scintillaEdit.Markers[Marker.FolderOpen].Symbol = CODEFOLDING_CIRCULAR ? MarkerSymbol.CircleMinus : MarkerSymbol.BoxMinus;
			scintillaEdit.Markers[Marker.FolderEnd].Symbol = CODEFOLDING_CIRCULAR ? MarkerSymbol.CirclePlusConnected : MarkerSymbol.BoxPlusConnected;
			scintillaEdit.Markers[Marker.FolderMidTail].Symbol = MarkerSymbol.TCorner;
			scintillaEdit.Markers[Marker.FolderOpenMid].Symbol = CODEFOLDING_CIRCULAR ? MarkerSymbol.CircleMinusConnected : MarkerSymbol.BoxMinusConnected;
			scintillaEdit.Markers[Marker.FolderSub].Symbol = MarkerSymbol.VLine;
			scintillaEdit.Markers[Marker.FolderTail].Symbol = MarkerSymbol.LCorner;

			// 启用自动折叠 
			scintillaEdit.AutomaticFold = (AutomaticFold.Show | AutomaticFold.Click | AutomaticFold.Change);

		}

		private void TextArea_MarginClick(object sender, MarginClickEventArgs e)
		{
			if (e.Margin == BOOKMARK_MARGIN)
			{
				// Do we have a marker for this line?
				const uint mask = (1 << BOOKMARK_MARKER);
				var line = scintillaEdit.Lines[scintillaEdit.LineFromPosition(e.Position)];
				if ((line.MarkerGet() & mask) > 0)
				{
					// Remove existing bookmark
					line.MarkerDelete(BOOKMARK_MARKER);
				}
				else
				{
					// Add bookmark
					line.MarkerAdd(BOOKMARK_MARKER);
				}
			}
		}

		#endregion


		#region Utils

		public static Color IntToColor(int rgb)
		{
			return Color.FromArgb(255, (byte)(rgb >> 16), (byte)(rgb >> 8), (byte)rgb);
		}

		public void InvokeIfNeeded(Action action)
		{
			if (this.InvokeRequired)
			{
				this.BeginInvoke(action);
			}
			else
			{
				action.Invoke();
			}
		}

		#endregion

		#endregion

		private async void buttonGet_Click(object sender, EventArgs e)
		{			
			if (textBoxModelName.Text == "")
			{
				ShowWarningDialog("请输入模型名称！");
			}
            else
            {
				var versionResult = await odooClient.GetVersionAsync();
				var loginResult = await odooClient.LoginAsync();
				if (loginResult.Failed)
				{
					ShowInfoDialog("登陆验证失败，请检查配置是否正确");
				}
				else if (loginResult.Succeed)
				{
					var tableName = textBoxModelName.Text;
					//var langName = comboBoxLanguage.SelectedValue.ToString();
					//var repository = new OdooRepository<IrModelOdooModel>(config);
					//repository.Config.Context.Language = langName;
					try
					{
                        var modelResult = await odooClient.GetModelAsync(tableName);
                        if (modelResult.Succeed)
                        {
                            //var model = OdooModelMapper.GetDotNetModel(tableName, modelResult.Value);
                            var model = ModelMapper.GenerateModelCode(tableName, modelResult.Value);
                            scintillaEdit.Text = model;
                        }
                        else
                        {
                            ShowErrorDialog("获取模型失败，请确认是否存在该模型！");
                        }
                        //model.Config.Context.Timezone = "AsiaChongqing"

                    }
					catch (Exception ex)
                    {
                        ShowErrorDialog(ex.ToString());
                    }
                }
			}
			
		}

        private void textBoxModelName_TextChanged(object sender, EventArgs e)
        {

        }
    }
}
